package com.example.demo.interceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import cn.hutool.core.date.DateUtil;
import com.example.demo.config.ConstantConfig;
import com.example.demo.entity.User;
import com.example.demo.entity.vo.ResponseResult;
import com.example.demo.enums.StatusCodeEnum;
import com.example.demo.exception.CustomException;
import com.example.demo.service.UserService;
import com.example.demo.util.AuthContextUtil;
import com.example.demo.util.NormalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.alibaba.fastjson.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;


/**
 * @description：token校验拦截器.
 * @author：lw
 * @since：2023/12/29
 **/

@Component
public class TokenInterceptor implements HandlerInterceptor{

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


        if (!(handler instanceof HandlerMethod)) return true; // 只拦截方法，不拦截静态资源

//         System.out.println("getRequestURI:"+request.getRequestURI());
//         return true;

        if("OPTIONS".equals(request.getMethod()))  return true;    // 不校验预检请求

        String request_token=request.getHeader(ConstantConfig.tokenFieldName);

        if(request_token==null) {
            responseNoLoginInfo(response, StatusCodeEnum.token_null);
            return false;
        }

        ValueOperations<String,String> redisOps=redisTemplate.opsForValue();
        String redis_token_value=redisOps.get(ConstantConfig.redis_login_token_prefix+request_token);
        if(redis_token_value==null){
            responseNoLoginInfo(response, StatusCodeEnum.token_invalid);
            return  false;
        }else{
            String ip=NormalUtil.getRequestIp(request);
            AuthContextUtil.IUser iUser=JSON.parseObject(redis_token_value, AuthContextUtil.IUser.class);
            System.out.println("token-validate-request username："+iUser.getUsername()+"  "+"ip："+ip+"   url："+request.getRequestURI());
            if(!iUser.getIp().equals(ip)) {   // 防止token被抓包获取使用
                redisTemplate.delete(ConstantConfig.redis_login_token_prefix+request_token);
                responseNoLoginInfo(response, StatusCodeEnum.token_invalid);
                return  false;
            }
           try{
                User newestUser=userService.getById(iUser.getId());

                   //if(iUser.getLastLoginTime().getTime()!=newestUser.getLastLoginTime().getTime()){   // 经测试，正常操作有时会差个1s，因此这种方法不可取
//                 String s1= DateUtil.format(iUser.getLastLoginTime(), "yyyy/MM/dd HH:mm");   // 精确到分比较
//                 String s2= DateUtil.format(newestUser.getLastLoginTime(), "yyyy/MM/dd HH:mm");
//                 if(!s1.equals(s2))
                    int l=(int) (iUser.getLastLoginTime().getTime() - newestUser.getLastLoginTime().getTime());
                    if(Math.abs(l) > 3000) {   // 允许3s内的误差，实在不行就精确到分进行比较
                        // 有新的登录，则旧的登录失效，保证只在一台设备登录
                        redisTemplate.delete(ConstantConfig.redis_login_token_prefix+request_token);
                        responseNoLoginInfo(response, StatusCodeEnum.token_invalid);
                        System.out.println(iUser.getUsername()+":新的登录使得旧登录失效  "+iUser.getLastLoginTime()+"——"+newestUser.getLastLoginTime());
                        return false;
                    }

           }catch (Exception e){
               e.printStackTrace();
           }
            AuthContextUtil.set(iUser);
//         redisTemplate.expire(ConstantConfig.redis_login_token_prefix+request_token, ConstantConfig.token_expire, ConstantConfig.token_expire_unit);
            return  true;
        }
    }


    private void responseNoLoginInfo(HttpServletResponse response,StatusCodeEnum statusCodeEnum) {
        ResponseResult<Object> result = ResponseResult.build(null,statusCodeEnum);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try (PrintWriter writer = response.getWriter()) {
            writer.print(JSON.toJSONString(result));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {
        AuthContextUtil.remove();
    }
}
